﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace ImageProcessing
{
	public static class ColorFilters
	{

		internal static Bitmap Saturation(Bitmap bmIn, double s, bool clamp)
		{
			double[][] adY = ColorConversions.ImagetoY(bmIn,true);
			int k;
			//double RY, GY, BY;
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height,bmIn.PixelFormat);

			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);
			Rectangle rectDest = new Rectangle(0, 0, bmOut.Width, bmOut.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectDest, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int destBytePP = Image.GetPixelFormatSize(bmOut.PixelFormat) / 8;
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			unsafe
			{
				byte* sptr = (byte*)(void*)srcPtr;
				byte* dptr = (byte*)(void*)destPtr;

				for (int j = 0; j < bmIn.Height; j++)
				{
					k = j * srcStride;
					for (int i = 0; i < bmIn.Width; i++)
					{

						dptr[k + i * srcBytePP] = (byte)Math.Max(0, Math.Min(255, ((s * (((sptr[k + i * srcBytePP]/255.0) - adY[i][j])) + adY[i][j])*255.0)));
						if (srcBytePP >= 3)
						{
							dptr[k + i * srcBytePP + 1] = (byte)Math.Max(0, Math.Min(255, (((s * ((sptr[k + i * srcBytePP + 1]/255.0) - adY[i][j])) + adY[i][j])*255.0)));
							dptr[k + i * srcBytePP + 2] = (byte)Math.Max(0, Math.Min(255, (((s * ((sptr[k + i * srcBytePP + 2]/255.0) - adY[i][j])) + adY[i][j])*255.0)));
							if (srcBytePP == 4)
							{
								dptr[k + i * srcBytePP + 3] = 255;
							} //end if
						} //end if
					} //end for
				} //end for

			} //end unsafe

			bmOut.UnlockBits(destBitData);
			bmIn.UnlockBits(srcBitData);
			return bmOut;
		}//end Saturation

		internal static Bitmap Hue(Bitmap bmIn, double theta, bool p)
		{
			double[][] adY = ColorConversions.ImagetoY(bmIn,true);
			int k,t;
			double RY, GY, BY;
			Bitmap bmOut = new Bitmap(bmIn.Width, bmIn.Height,bmIn.PixelFormat);

			#region Two image pointer setup
			BitmapData destBitData;
			BitmapData srcBitData;
			Rectangle rectSrc = new Rectangle(0, 0, bmIn.Width, bmIn.Height);
			Rectangle rectDest = new Rectangle(0, 0, bmOut.Width, bmOut.Height);

			srcBitData = bmIn.LockBits(rectSrc, ImageLockMode.ReadOnly, bmIn.PixelFormat);
			destBitData = bmOut.LockBits(rectDest, ImageLockMode.WriteOnly, bmOut.PixelFormat);
			int destBytePP = Image.GetPixelFormatSize(bmOut.PixelFormat) / 8;
			int srcBytePP = Image.GetPixelFormatSize(bmIn.PixelFormat) / 8;
			IntPtr destPtr = destBitData.Scan0;
			IntPtr srcPtr = srcBitData.Scan0;
			int srcStride = srcBitData.Stride;
			int destStride = destBitData.Stride;
			#endregion

			unsafe
			{
				byte* sptr = (byte*)(void*)srcPtr;
				byte* dptr = (byte*)(void*)destPtr;

				for (int j = 0; j < bmIn.Height; j++)
				{
					k = j * srcStride;
					for (int i = 0; i < bmIn.Width; i++)
					{
						t = i *srcBytePP;
						RY = sptr[k + t] / 255.0 - adY[i][j];
						BY = sptr[k + t + 2] / 255.0 - adY[i][j];
						//use GY as temp
						GY = BY * Math.Cos(theta) - RY * Math.Sin(theta);
						RY = BY * Math.Sin(theta) + RY * Math.Cos(theta);
						BY = GY;
						GY = -.51 * RY - 0.19 * BY;
						dptr[k + t] = (byte)Math.Max(0, Math.Min(255, (RY + adY[i][j]) * 255.0));
						if (srcBytePP >= 3)
						{
							dptr[k + t + 1] = (byte)Math.Max(0, Math.Min(255, (GY + adY[i][j]) * 255.0));
							dptr[k + t + 2] = (byte)Math.Max(0, Math.Min(255, (BY + adY[i][j]) * 255.0));
							if (srcBytePP == 4)
							{
								dptr[k + t + 3] = 255;
							} //end if
						}//end if

					} //end for
				} //end for

			}//end unsafe
			bmIn.UnlockBits(srcBitData);
			bmOut.UnlockBits(destBitData);

			return bmOut;
		}

		public static double[, ,] rgb(double[, ,] adImage, int nWidth, int nHeight, double[] adArgs)
		{
			double adTotal;
			double[, ,] adOut = new double[nWidth, nHeight, 3];

			for (int j = 0; j < nHeight; j++)
			{
				for (int i = 0; i < nWidth; i++)
				{
					adTotal = adImage[i,j,0] + adImage[i,j,1] + adImage[i,j,2];
					adOut[i, j, 0] = adArgs[0] * (adImage[i, j, 0] / (adTotal));
					adOut[i, j, 1] = adArgs[1] * (adImage[i, j, 1] / (adTotal));
					adOut[i, j, 2] = adArgs[2] * (adImage[i, j, 2] / (adTotal));

				} //end for
			} //end for

			return adOut;
		}
	}
}
